{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# 图像分类：VGG NET架构 "
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "a427f3dcb83b716c"
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import keras\n",
    "import tensorflow as tf\n",
    "from keras.models import Sequential\n",
    "from keras.layers import Dense,Dropout,Conv2D,MaxPooling2D,Flatten"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:54:33.069540900Z",
     "start_time": "2024-01-14T06:54:28.695486300Z"
    }
   },
   "id": "e826281e60b45c74"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 模型构建"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "6dd9986efc788181"
  },
  {
   "cell_type": "markdown",
   "source": [
    "### VGG块构建"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "924c05d7b6eedab6"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [],
   "source": [
    "def vgg_block(num_conv,num_filters):\n",
    "    # 序列模型\n",
    "    sq = Sequential()\n",
    "    for _ in range(num_conv):\n",
    "        sq.add(Conv2D(num_filters,activation=\"relu\",kernel_size=3,padding=\"same\"))\n",
    "    sq.add(MaxPooling2D(pool_size=2,strides=2))\n",
    "    return sq"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:54:33.965906800Z",
     "start_time": "2024-01-14T06:54:33.931922100Z"
    }
   },
   "id": "13e889a187ac6e2a"
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 构建模型"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "ff9b9fcda1508568"
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [],
   "source": [
    "def vgg(conv_arch):\n",
    "    # 序列模型\n",
    "    model = Sequential()\n",
    "    # 生成卷积部分\n",
    "    for(num_conv,num_filters) in conv_arch:\n",
    "        model.add(vgg_block(num_conv, num_filters))\n",
    "    # 全连接层\n",
    "    model.add(Sequential([\n",
    "        # 展评\n",
    "        Flatten(),\n",
    "        #全链路层\n",
    "        Dense(4096,activation=\"relu\"),\n",
    "        # 随机失活\n",
    "        Dropout(0.5),\n",
    "        Dense(4096,activation=\"relu\"),\n",
    "        Dropout(0.5),\n",
    "        # 输出层\n",
    "        Dense(10,activation=\"softmax\"),\n",
    "    ]))\n",
    "    return model"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:54:37.684640700Z",
     "start_time": "2024-01-14T06:54:37.654639100Z"
    }
   },
   "id": "2550da7be214bb38"
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [],
   "source": [
    "#卷积块参数\n",
    "conv_arch = (\n",
    "    (2,64),  # 2个卷积层，64个卷积核\n",
    "    (2,128), # 2个卷积层，128个卷积核\n",
    "    (3,256), # 3个卷积层，256个卷积核\n",
    "    (3,512), # 3个卷积层，512个卷积核\n",
    "    (3,512)  # 3个卷积层，512个卷积核\n",
    ")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:54:41.388662500Z",
     "start_time": "2024-01-14T06:54:41.364626900Z"
    }
   },
   "id": "9371efc45dc350b4"
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [],
   "source": [
    "# 调用函数生成vggnet\n",
    "vggnet = vgg(conv_arch)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:54:42.619851200Z",
     "start_time": "2024-01-14T06:54:42.502845500Z"
    }
   },
   "id": "8cbd97acecd9cfa7"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "x = tf.random.uniform((1,224,224,1))\n",
    "y = vggnet(x)"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "8efd1ed2c08dc015"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "vggnet.summary()"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "9485d9a5c1cc5b18"
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [],
   "source": [
    "from keras.datasets import mnist\n",
    "\n",
    "(train_image, train_label), (test_image, test_label) = mnist.load_data()\n",
    "\n",
    "# 维度调整,转换成(60000, 28, 28, 1)\n",
    "train_image = np.reshape(train_image,  # 数据源\n",
    "                         (\n",
    "                             train_image.shape[0],\n",
    "                             train_image.shape[1],\n",
    "                             train_image.shape[2],\n",
    "                             1  # 通道数1\n",
    "                         ))\n",
    "# 维度调整,转换成(60000, 28, 28, 1)\n",
    "test_image = np.reshape(test_image,  # 数据源\n",
    "                        (\n",
    "                            test_image.shape[0],\n",
    "                            test_image.shape[1],\n",
    "                            test_image.shape[2],\n",
    "                            1  # 通道数1\n",
    "                        ))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:54:48.850555Z",
     "start_time": "2024-01-14T06:54:48.455968200Z"
    }
   },
   "id": "20710e9f4029f717"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "train_image = tf.image.resize_with_pad(train_image[:], 224, 224)\n",
    "test_image = tf.image.resize_with_pad(test_image[:], 224, 224)"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "39ff6ff5a0f3c632"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   },
   "id": "db03086e8497d48d"
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [],
   "source": [
    "# 对训练数据进行抽样 可以不用\n",
    "def get_train(size):\n",
    "    # 随机生成index\n",
    "    index = np.random.randint(0, train_image.shape[0], size)\n",
    "    # 选择图像进行resize\n",
    "    resized_image = tf.image.resize_with_pad(train_image[index], 224, 224)\n",
    "    return resized_image.numpy(), train_label[index]"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:55:23.454773200Z",
     "start_time": "2024-01-14T06:55:23.423774800Z"
    }
   },
   "id": "afb9c7e2e36efce6"
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [],
   "source": [
    "# 对测试数据进行抽样 可以不用\n",
    "def get_test(size):\n",
    "    # 随机生成index\n",
    "    index = np.random.randint(0, test_image.shape[0], size)\n",
    "    # 选择图像进行resize\n",
    "    resized_image = tf.image.resize_with_pad(test_image[index], 224, 224)\n",
    "    return resized_image.numpy(), test_label[index]"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:55:24.000484700Z",
     "start_time": "2024-01-14T06:55:23.987532300Z"
    }
   },
   "id": "1118dd1ca9fd0d94"
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "outputs": [],
   "source": [
    "# 抽样结果\n",
    "train_image, train_label = get_train(256)\n",
    "test_image, test_label = get_test(128)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T07:13:03.320185600Z",
     "start_time": "2024-01-14T07:13:03.206280100Z"
    }
   },
   "id": "8a1c0697dbed7bb1"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   },
   "id": "4f129b1df861bc3b"
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [],
   "source": [
    "opt = vggnet.compile(\n",
    "    optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),\n",
    "    loss=tf.keras.losses.sparse_categorical_crossentropy,\n",
    "    metrics=[\"accuracy\"]\n",
    ")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T06:55:32.564058Z",
     "start_time": "2024-01-14T06:55:32.284175400Z"
    }
   },
   "id": "41f9c7c2c6f58aba"
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/5\n",
      "1/1 [==============================] - 50s 50s/step - loss: 2.1560 - accuracy: 0.3633 - val_loss: 1.9900 - val_accuracy: 0.5234\n",
      "Epoch 2/5\n",
      "1/1 [==============================] - 49s 49s/step - loss: 2.0147 - accuracy: 0.4219 - val_loss: 1.7137 - val_accuracy: 0.5625\n",
      "Epoch 3/5\n",
      "1/1 [==============================] - 48s 48s/step - loss: 1.7659 - accuracy: 0.5273 - val_loss: 1.2088 - val_accuracy: 0.6562\n",
      "Epoch 4/5\n",
      "1/1 [==============================] - 49s 49s/step - loss: 1.4170 - accuracy: 0.5547 - val_loss: 1.0680 - val_accuracy: 0.6875\n",
      "Epoch 5/5\n",
      "1/1 [==============================] - 49s 49s/step - loss: 1.3998 - accuracy: 0.5078 - val_loss: 2.6094 - val_accuracy: 0.2188\n"
     ]
    }
   ],
   "source": [
    "his = vggnet.fit(train_image,\n",
    "                train_label,\n",
    "                batch_size=512,\n",
    "                epochs=5,\n",
    "                # validation_split=0.1,\n",
    "                validation_data=(test_image,test_label),\n",
    "                verbose=1\n",
    "                )"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T07:17:16.435812200Z",
     "start_time": "2024-01-14T07:13:11.303126800Z"
    }
   },
   "id": "222ab1966fc6048d"
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4/4 [==============================] - 3s 786ms/step - loss: 2.6094 - accuracy: 0.2188\n"
     ]
    },
    {
     "data": {
      "text/plain": "[2.609447479248047, 0.21875]"
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vggnet.evaluate(test_image, test_label)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-14T07:44:39.364351800Z",
     "start_time": "2024-01-14T07:44:35.913961500Z"
    }
   },
   "id": "9ec91eeddbde1022"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "vggnet.save('手写字识别vggnet.h5') # 学习跑得很慢，可能要用GPU"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "9705711b0f6e28e7"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
